package com.haidechizi.i18n.common.execute.strategy;

import com.google.common.base.Stopwatch;
import com.haidechizi.i18n.common.annotation.I18nField;
import com.haidechizi.i18n.common.annotation.I18nModel;
import com.haidechizi.i18n.common.enums.annotation.I18nEnumField;
import com.haidechizi.i18n.common.enums.service.TranslateService;
import com.haidechizi.i18n.common.execute.AbstractTranslateExecute;
import com.haidechizi.i18n.common.support.I18nReflectUtils;
import com.haidechizi.i18n.common.translate.Translator;
import com.haidechizi.i18n.common.utils.GlobalUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.reflect.FieldUtils;
import org.springframework.beans.factory.annotation.Autowired;

import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
 * 使用简单递归进行国际化
 */
@Slf4j
public class SimpleTranslateExecute extends AbstractTranslateExecute {

    private static final String NAME = "simple";

    @Autowired(required = false)
    private TranslateService translateService;

    @Override
    public String name() {
        return NAME;
    }

    @Override
    public void processI18nFields(List<Object> models) {
        if (CollectionUtils.isEmpty(models)) {
            return;
        }
        Object firstModel = models.get(0);
        if (firstModel == null) {
            log.warn("当前对象为空: {}", models);
            return;
        }
        Class<?> clazz = firstModel.getClass();
        I18nModel i18nAnnotation = I18nReflectUtils.getI18nModelAnnotation(clazz);
        if (i18nAnnotation == null) {
            return;
        }

        // 判断是否是当前系统的对象（上游系统的国际化由上游系统处理，只翻译当前系统的对象）
        // 只判断最外层的对象
        if (!isCurrentSystemObject(i18nAnnotation.systemCode())) {
            return;
        }

        //简单属性处理
        processSimpleField(models, I18nReflectUtils.getSimpleFieldsListWithAnnotation(clazz));

        //如果I18nField里面有完备的信息，说明他在一个组合的DTO里面，不属于单独的一个域对象，单独使用自己的元信息查询
        processCombinedField(models, I18nReflectUtils.getCombinedFieldsListWithAnnotation(clazz));

        //定制逻辑的field处理
        processCustomField(models, I18nReflectUtils.getCustomFieldsListWithAnnotation(clazz));

        // 处理枚举字段的国际化
        processEnumField(models, I18nReflectUtils.getEnumFields(clazz));

        //将不属于需要国际化的字段提取出来，再次递归走assembleI18nInfo的流程，处理嵌套的需要国际化的对象
        models.stream().forEach(model -> {

            I18nReflectUtils.getOtherFieldsListWithAnnotation(clazz).forEach(el -> {
                try {
                    assembleI18nInfo(FieldUtils.readField(model, el.getName(), true));
                } catch (IllegalAccessException e) {
                    log.error("assembleI18nInfo", e);
                }
            });
        });

    }

    private void processCombinedField(List<Object> models, List<Field> combinedFields) {
        if (CollectionUtils.isEmpty(combinedFields)) {
            return;
        }
        combinedFields.forEach(combinedField -> {
            I18nField i18nField = I18nReflectUtils.getI18nFieldAnnotation(combinedField);
            String systemCode = i18nField.systemCode();
            String businessCode = i18nField.businessCode();
            String businessKeyName = i18nField.businessKey();
            String fieldMappingInPlatform = i18nField.value();
            if (StringUtils.isBlank(fieldMappingInPlatform)) {
                log.warn("i18nField.value is null ,businessCode: {}", businessCode);
                return;
            }
            List<String> businessKeyListOfTheCombinedField = extractBusinessKeyList((List) models, businessKeyName);

            Map<String, Map<String, String>> idFieldsMapOfCombinedField = i18nInfoUtils.queryLocaleInfo(systemCode,
                    businessCode, GlobalUtils.getLanguage(), businessKeyListOfTheCombinedField);
            if (idFieldsMapOfCombinedField.isEmpty()) {
                log.debug("国际化平台无相关国际化数据，跳过循环,系统Code：{}, 业务code：{}, 语言：{}, 业务主键:{},国际化结果：{}",
                        systemCode, businessCode, GlobalUtils.getLanguage(), businessKeyListOfTheCombinedField,
                        idFieldsMapOfCombinedField);
                return;
            }
            models.stream().forEach(model -> {
                try {
                    Object businessKeyValue = FieldUtils.readField(model, businessKeyName, true);
                    if (businessKeyValue != null) {
                        String businessKey = String.valueOf(businessKeyValue);
                        Map<String, String> fieldsMap = idFieldsMapOfCombinedField.get(businessKey);
                        if (fieldsMap != null && !fieldsMap.isEmpty()) {
                            String substitution = fieldsMap.get(fieldMappingInPlatform);
                            if (StringUtils.isNotEmpty(substitution)) {
                                log.debug("====processCombinedField====>参数名字：{},========>值：{}",
                                        combinedField.getName(), substitution);
                                FieldUtils.writeField(combinedField, model, substitution, true);
                            }
                        }
                    }
                } catch (Exception e) {
                    log.error("error:", e);
                }
            });
        });
    }

    private void processCustomField(List<Object> models, List<Field> customFields) {
        if (CollectionUtils.isEmpty(customFields)) {
            return;
        }
        customFields.forEach(customField -> {
            I18nField i18nField = I18nReflectUtils.getI18nFieldAnnotation(customField);
            String metaCalculator = i18nField.metaCalculator();
            Translator calculator = i18nInfoUtils.getTranslator(metaCalculator);
            if (calculator == null) {
                log.error("自定义处理器：{} ,不存在，请查看代码", metaCalculator);
                return;
            }
            calculator.translate(models);
        });
    }

    private void processSimpleField(List<Object> models, List<Field> simpleFields) {
        if (CollectionUtils.isEmpty(simpleFields)) {
            return;
        }
        Object firstModel = models.get(0);
        if (firstModel == null) {
            return;
        }
        I18nModel i18nAnnotation = I18nReflectUtils.getI18nModelAnnotation(firstModel.getClass());
        if (i18nAnnotation == null) {
            return;
        }
        //locale是dubbo调用时，被调用方传入的
        String languageName = GlobalUtils.getLanguage();
        String systemCodeModel = i18nAnnotation.systemCode();
        String businessCodeModel = i18nAnnotation.businessCode();
        String businessKeyNameModel = i18nAnnotation.businessKey();

        List<String> businessKeyList = extractBusinessKeyList(models, businessKeyNameModel);
        Stopwatch stopwatch = Stopwatch.createStarted();
        Map<String, Map<String, String>> idFieldsMapModel = i18nInfoUtils.queryLocaleInfo(systemCodeModel,
                businessCodeModel, languageName, businessKeyList);
        log.debug("========国际化语言返回结果耗時:========> " + stopwatch.elapsed(TimeUnit.MILLISECONDS) + "ms");
        if (idFieldsMapModel.isEmpty()) {
            log.debug("国际化平台无相关国际化数据，跳过循环,系统Code：{}, 业务code：{}, 语言：{}, 业务主键:{},国际化结果：{}",
                    systemCodeModel, businessCodeModel, languageName, businessKeyList, idFieldsMapModel);
            return;
        }
        models.stream().filter(Objects::nonNull).forEach(model -> {
            try {
                String id = String.valueOf(FieldUtils.readField(model, businessKeyNameModel, true));
                Map<String, String> fieldMap = idFieldsMapModel.get(id);
                if (fieldMap != null && !fieldMap.isEmpty()) {
                    simpleFields.stream().forEach(field -> {
                        I18nField i18nField = I18nReflectUtils.getI18nFieldAnnotation(field);
                        String nameMappingInPlatform = i18nField.value();
                        if (StringUtils.isBlank(nameMappingInPlatform)) {
                            log.warn("i18nField.value is null ,businessCode: {}", businessCodeModel);
                            return;
                        }
                        String substitution = fieldMap.get(nameMappingInPlatform);
                        try {
                            if (StringUtils.isNotBlank(substitution)) {
                                FieldUtils.writeField(field, model, substitution, true);
                            } else {
                                log.debug("字段：{},原始值：{},替换值：{}", field.getName(), nameMappingInPlatform, substitution);
                            }
                        } catch (Exception e) {
                            log.error("assemble field error", e);
                        }
                    });
                }
            } catch (Exception e) {
                log.error("assemble field error", e);
            }
        });
    }

    /**
     * 对枚举字段进行国际化
     * <p>
     * 需要依赖静态国际化的功能
     *
     * @param models
     * @param enumFields
     * @see TranslateService
     */
    private void processEnumField(List<Object> models, List<Field> enumFields) {
        if (CollectionUtils.isEmpty(enumFields)) {
            return;
        }
        enumFields.forEach(enumField -> {
            try {
                I18nEnumField i18nEnumField = I18nReflectUtils.getEnumFieldAnnotation(enumField);
                // 当前对象中的enum唯一键对应的field名称
                String businessKey = i18nEnumField.businessKey();
                // 枚举中唯一键对应的字段名称
                String enumKey = i18nEnumField.enumKey();
                // 枚举对象
                Class<? extends Enum> clazz = i18nEnumField.clazz();
                // 获取枚举类中的静态对象
                Enum[] enumConstants = clazz.getEnumConstants();
                Map<String, Enum> enumMap = new HashMap<>();
                Field declaredField = clazz.getDeclaredField(enumKey);
                declaredField.setAccessible(true);
                for (Enum e : enumConstants) {
                    Object o = declaredField.get(e);
                    enumMap.put(String.valueOf(o), e);
                }
                models.forEach(model -> {
                    try {
                        // 获取当前对象中的枚举value
                        Object businessKeyValue = FieldUtils.readField(model, businessKey, true);
                        String value;
                        if (businessKeyValue == null || StringUtils.isBlank(value = String.valueOf(businessKeyValue))) {
                            return;
                        }
                        // 获取枚举对象
                        Enum anEnum = enumMap.get(value);
                        if (anEnum == null) {
                            return;
                        }
                        // 对枚举对象进行国际化
                        String forEnum = translateService.translateForEnum(anEnum);
                        if (StringUtils.isBlank(forEnum)) {
                            return;
                        }
                        // 将国际化的结果写回到当前对象
                        FieldUtils.writeField(enumField, model, forEnum, true);
                    } catch (Exception e) {
                        log.error("获取对象中的值出现异常", e);
                    }
                });
            } catch (Exception e) {
                log.error("枚举国际化异常", e);
            }

        });

    }

}
